#include "head.h"
//自定义的读函数，自带偏移量
int recvn(int netFd,void *p, int n){
    int total = 0;
    int ret;
    char *pTmp = (char *)p;
    while(total < n){
        ret = recv(netFd,pTmp+total,n-total,0);
        ERROR_CHECK(ret,-1,"recv");
        total+= ret;
    }
    return 0;
}
//接收服务端发送过来的文件
int recvFile(int netFd){
    int dataLength;
    char name[1024] = {0};
    int ret =recvn(netFd,&dataLength,sizeof(int));//先收火车头
    ERROR_CHECK(ret,-1,"recv");
    ret = recvn(netFd,name, dataLength);//再收文件名
    ERROR_CHECK(ret,-1,"recv");
    int fd = open(name, O_RDWR|O_CREAT, 0666);
    ERROR_CHECK(fd,-1,"open");
    char buf[1024] = {0};
    long fileSize;
    recvn(netFd,&dataLength,sizeof(int));//先收火车头
    recvn(netFd,&fileSize,sizeof(fileSize));//再收文件长度
    printf("fileSize = %ld\n", fileSize);

    off_t downSize = 0;
    off_t lastSize = 0;
    off_t slice = fileSize/1000;
    struct timeval begTime,endTime;
    gettimeofday(&begTime,NULL);
    while(1){
        ret = recvn(netFd,&dataLength,sizeof(int));//先收火车头
        ERROR_CHECK(ret,-1,"recv");
        if(dataLength==0){
            break;
        }
        if(dataLength != 1000){
            printf("dataLength = %d\n", dataLength);
        }
        ret = recvn(netFd,buf,dataLength);
        ERROR_CHECK(ret,-1,"recv");
        downSize += dataLength;
        if(downSize-lastSize > slice){
            printf("%5.2lf%s\r", 100.0*downSize/fileSize,"%");
            fflush(stdout);
            lastSize = downSize;
        }
        write(fd,buf,dataLength);
    }
    printf("100.00%s\n", "%");
    gettimeofday(&endTime,NULL);
    printf("total time = %ld\n", 1000000*(endTime.tv_sec-begTime.tv_sec) + endTime.tv_usec-begTime.tv_usec);
}
//上传客户端文件去服务器
int upFile(int netFd,char* fileName){
    train_t t;
    int length = strlen(fileName);
    bzero(t.buf,sizeof(t.buf));
    t.dataLength = length;
    strcpy(t.buf,fileName);
    
    int fd = open(fileName, O_RDWR);
    ERROR_CHECK(fd,-1,"open");
    int ret = send(netFd,&t,sizeof(t.dataLength)+ t.dataLength,MSG_NOSIGNAL);//发送文件名
    ERROR_CHECK(ret,-1,"send");
    struct stat statbuf;
    ret = fstat(fd,&statbuf);//获取文件的总大小
    ERROR_CHECK(ret,-1,"fstat");
    t.dataLength = sizeof(statbuf.st_size);//把文件的大小装入小火车
    memcpy(t.buf,&statbuf.st_size,sizeof(statbuf.st_size));
    send(netFd,&t,sizeof(t.dataLength)+t.dataLength,MSG_NOSIGNAL);
    
    char *p = (char *)mmap(NULL,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    ERROR_CHECK(p,MAP_FAILED,"mmap");
    off_t total = 0;
    while(total < statbuf.st_size){
        if(statbuf.st_size - total < sizeof(t.buf)){
            //最后一次发送
            t.dataLength = statbuf.st_size-total;
        }
        else{
            t.dataLength = sizeof(t.buf);
        }
        memcpy(t.buf,p+total,t.dataLength);//把数据装入火车车厢
        int ret = send(netFd,&t,sizeof(t.dataLength)+t.dataLength,MSG_NOSIGNAL);
        ERROR_CHECK(ret,-1,"send");
        total += t.dataLength;
    }
    munmap(p,statbuf.st_size);
    t.dataLength = 0;
    send(netFd,&t,sizeof(t.dataLength),0);
    //发送终止
    close(fd);
}
//添加监听
int epollAdd(int fd, int epfd){
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = fd;
    int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&event);
    ERROR_CHECK(ret,-1,"epoll_ctl");
    return 0;
}
//删除监听
int epollDel(int fd, int epfd){
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = fd;
    int ret = epoll_ctl(epfd,EPOLL_CTL_DEL,fd,&event);
    ERROR_CHECK(ret,-1,"epoll_ctl");
    return 0;
}
//子线程工作函数 1接收 2发送
void *threadFunc1(void* mycmd){//gets
    commond_t* cmd=(commond_t*)mycmd;
    puts("I am child pthread,recvfile:");
    //子线程与服务器建立新连接，用新socket以防与主线程冲突
    int sockFd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(cmd->port));
    addr.sin_addr.s_addr = inet_addr(cmd->addr);
    connect(sockFd, (struct sockaddr *)&addr, sizeof(addr));
    cmd->sockFd=sockFd;
    //发送用户名与token给服务端
    send(sockFd,cmd->token,strlen(cmd->token),0);
    puts(cmd->usrName);
    send(sockFd,cmd->usrName,strlen(cmd->usrName),0);
    //把命令发给服务端
    send(sockFd,cmd->buf,strlen(cmd->buf),0);
    recvFile(cmd->sockFd);
    pthread_exit(NULL);
}
void *threadFunc2(void* mycmd){//puts
    commond_t* cmd=(commond_t*)mycmd;
    puts("I am child pthread,upFile:");
    //子线程与服务器建立新连接，用新socket以防与主线程冲突
    int sockFd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(cmd->port));
    addr.sin_addr.s_addr = inet_addr(cmd->addr);
    connect(sockFd, (struct sockaddr *)&addr, sizeof(addr));
    cmd->sockFd=sockFd;
    //发送用户名与token给服务端
    //printf("len = %lu\n",strlen(cmd->usrName));
    send(sockFd,cmd->token,strlen(cmd->token),0);
    //puts(cmd->usrName);
    send(sockFd,cmd->usrName,strlen(cmd->usrName),0);
    //把命令发给服务端
    send(sockFd,cmd->buf,strlen(cmd->buf),0);
    puts(cmd->buf);
    upFile(cmd->sockFd,cmd->filename);
    pthread_exit(NULL);
}